﻿namespace MicroCloud.Utils
{
    /// <summary>
    /// 字符串 <see cref="string"/> 类型的扩展辅助操作类
    /// </summary>
    public static partial class StringExtensions
    {
        /// <summary>
        /// 所有正则表达式元字符
        /// </summary>
        private static readonly string[] REGEX_META_CHARS = ["\\", ".", "^", "$", "*", "+", "?", "{", "}", "(", ")", "[", "]"];

        #region 类型转换
        public static Guid ToGuid(this string value)
        {
            Guid.TryParse(value, out Guid @guid);
            return @guid;
        }

        public static bool ToBoolean(this string value)
        {
            bool.TryParse(value, out bool @bool);
            return @bool;
        }

        /// <summary>转化为Byte型</summary>
        public static Byte ToByte(this string value)
        {
            Byte.TryParse(value, out Byte @byte);
            return @byte;
        }

        /// <summary> 转化为int16型</summary>
        public static short ToShort(this string value)
        {
            short.TryParse(value, out short @short);
            return @short;
        }

        /// <summary>转化为int32型</summary>
        public static int ToInt(this string value)
        {
            Int32.TryParse(value, out int @int);
            return @int;
        }

        /// <summary>转化为int64型</summary>
        public static long ToLong(this string value)
        {
            long.TryParse(value, out long @long);
            return @long;
        }

        /// <summary>转化为Float型</summary>
        public static float ToFloat(this string value)
        {
            float.TryParse(value, out float @float);
            return @float;
        }

        /// <summary>转化为Double型</summary>
        public static double ToDouble(this string value)
        {
            double.TryParse(value, out double @double);
            return @double;
        }

        /// <summary>转化为decimal型</summary>
        public static decimal ToDecimal(this string value)
        {
            decimal.TryParse(value, out decimal @decimal);
            return @decimal;
        }

        /// <summary>转化为日期为空里返回NullSqlDateTime,byark</summary>
        public static DateTime ToDateTime(this string value)
        {
            DateTime.TryParse(value, out DateTime @dateTime);
            return @dateTime;
        }

        /// <summary>获取字符串长度，按中文2位，英文1位进行计算</summary>
        public static int CharCodeLength(this string value)
        {
            int len = 0;
            foreach (var c in value.ToCharArray())
                if (c < 128)
                    len++;
                else
                    len += 2;
            return len;
        }

        #endregion

        #region "正则表达式"
        #region "指示所指定的正则表达式在指定的输入字符串中是否找到了匹配项"
        /// <summary>
        /// 指示所指定的正则表达式在指定的输入字符串中是否找到了匹配项
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <param name="pattern">要匹配的正则表达式模式</param>
        /// <param name="isContains">是否包含，否则全匹配</param>
        /// <returns>如果正则表达式找到匹配项，则为 true；否则，为 false</returns>
        public static bool IsMatch(this string value, string pattern, bool isContains = true)
        {
            if (value == null)
            {
                return false;
            }
            return isContains
                ? Regex.IsMatch(value, pattern)
                : Regex.Match(value, pattern).Success;
        }
        #endregion
        #region "在指定的输入字符串中搜索指定的正则表达式的第一个匹配项"
        /// <summary>
        /// 在指定的输入字符串中搜索指定的正则表达式的第一个匹配项
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <param name="pattern">要匹配的正则表达式模式</param>
        /// <returns>一个对象，包含有关匹配项的信息</returns>
        public static string Match(this string value, string pattern)
        {
            if (value == null)
            {
                return null;
            }
            return Regex.Match(value, pattern).Value;
        }
        #endregion
        #region "在指定的输入字符串中匹配并替换符合指定正则表达式的子串"
        /// <summary>
        /// 在指定的输入字符串中匹配并替换符合指定正则表达式的子串
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <param name="pattern">要匹配的正则表达式模式</param>
        /// <param name="replacement">替换字符串</param>
        /// <returns></returns>
        public static string ReplaceRegex(this string value, string pattern, string replacement)
        {
            if (value == null)
            {
                return null;
            }

            return Regex.Replace(value, pattern, replacement);
        }
        #endregion
        #region "在指定的输入字符串中搜索指定的正则表达式的所有匹配项的字符串集合"
        /// <summary>
        /// 在指定的输入字符串中搜索指定的正则表达式的所有匹配项的字符串集合
        /// </summary>
        /// <param name="value"> 要搜索匹配项的字符串 </param>
        /// <param name="pattern"> 要匹配的正则表达式模式 </param>
        /// <returns> 一个集合，包含有关匹配项的字符串值 </returns>
        public static IEnumerable<string> Matches(this string value, string pattern)
        {
            if (value == null)
            {
                return Array.Empty<string>();
            }
            MatchCollection matches = Regex.Matches(value, pattern);
            return from Match match in matches select match.Value;
        }
        #endregion
        #region "在指定的输入字符串中匹配第一个数字字符串"
        /// <summary>
        /// 在指定的输入字符串中匹配第一个数字字符串
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <returns></returns>
        public static string MatchFirstNumber(this string value)
        {
            MatchCollection matches = Regex.Matches(value, @"\d+");
            if (matches.Count == 0)
            {
                return string.Empty;
            }
            return matches[0].Value;
        }
        #endregion
        #region "在指定字符串中匹配最后一个数字字符串"
        /// <summary>
        /// 在指定字符串中匹配最后一个数字字符串
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <returns></returns>
        public static string MatchLastNumber(this string value)
        {
            MatchCollection matches = Regex.Matches(value, @"\d+");
            if (matches.Count == 0)
            {
                return string.Empty;
            }
            //return matches[matches.Count - 1].Value;
            return matches[^1].Value;
        }
        #endregion
        #region "在指定字符串中匹配所有数字字符串"
        /// <summary>
        /// 在指定字符串中匹配所有数字字符串
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <returns></returns>
        public static IEnumerable<string> MatchNumbers(this string value)
        {
            return value.Matches(@"\d+");
        }
        #endregion
        #region "检测指定字符串中是否包含数字"
        /// <summary>
        /// 检测指定字符串中是否包含数字
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <returns></returns>
        public static bool IsMatchNumber(this string value)
        {
            return value.IsMatch(@"\d");
        }
        #endregion
        #region "检测指定字符串是否全部为数字并且长度等于指定长度"
        /// <summary>
        /// 检测指定字符串是否全部为数字并且长度等于指定长度
        /// </summary>
        /// <param name="value">要搜索匹配项的字符串</param>
        /// <param name="length">指定长度</param>
        /// <returns></returns>
        public static bool IsMatchNumber(this string value, int length)
        {
            Regex regex = new(@"^\d{" + length + "}$");
            return regex.IsMatch(value);
        }
        #endregion
        #region "截取指定字符串之间的字符串"
        /// <summary>
        /// 截取指定字符串之间的字符串
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="startString">起始字符串</param>
        /// <param name="endStrings">结束字符串，可多个</param>
        /// <returns>返回的中间字符串</returns>
        public static string Substring(this string source, string startString, params string[] endStrings)
        {
            if (source.IsMissing())
            {
                return string.Empty;
            }
            int startIndex = 0;
            if (!string.IsNullOrEmpty(startString))
            {
                startIndex = source.IndexOf(startString, StringComparison.OrdinalIgnoreCase);
                if (startIndex < 0)
                {
                    //throw new InvalidOperationException(string.Format("在源字符串中无法找到“{0}”的子串位置", startString));
                    throw new InvalidOperationException(I18N.T("在源字符串中无法找到 {0} 的子串位置", startString));
                }
                startIndex += startString.Length;
            }
            int endIndex = source.Length;
            endStrings = endStrings.OrderByDescending(m => m.Length).ToArray();
            foreach (string endString in endStrings)
            {
                if (string.IsNullOrEmpty(endString))
                {
                    endIndex = source.Length;
                    break;
                }
                endIndex = source.IndexOf(endString, startIndex, StringComparison.OrdinalIgnoreCase);
                if (endIndex < 0 || endIndex < startIndex)
                {
                    continue;
                }
                break;
            }
            if (endIndex < 0 || endIndex < startIndex)
            {
                //throw new InvalidOperationException(string.Format("在源字符串中无法找到“{0}”的子串位置", endStrings.ExpandAndToString()));
                throw new InvalidOperationException(I18N.T("在源字符串中无法找到 {0} 的子串位置", endStrings.ExpandAndToString()));
            }

            int length = endIndex - startIndex;
            return source.Substring(startIndex, length);
        }
        #endregion
        #region "用正则表达式截取字符串"
        /// <summary>
        /// 用正则表达式截取字符串
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="startString">起始字符串</param>
        /// <param name="endString">结束字符串</param>
        /// <returns></returns>
        public static string Substring2(this string source, string startString, string endString)
        {
            return source.Substring2(startString, endString, false);
        }
        #endregion
        #region "用正则表达式截取字符串"
        /// <summary>
        /// 用正则表达式截取字符串
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="startString">起始字符串</param>
        /// <param name="endString">结束字符串</param>
        /// <param name="containsEmpty">包含空项</param>
        /// <returns></returns>
        public static string Substring2(this string source, string startString, string endString, bool containsEmpty)
        {
            if (source.IsMissing())
            {
                return string.Empty;
            }
            string inner = containsEmpty ? "\\s\\S" : "\\S";
            string result = source.Match(string.Format("(?<={0})([{1}]+?)(?={2})", startString, inner, endString));
            return result.IsMissing() ? null : result;
        }
        #endregion

        #region "是否电子邮件"
        /// <summary>
        /// 是否电子邮件
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsEmail(this string value)
        {
            //const string pattern = @"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$";
            string pattern = string.Format("^{0}$", RegexPatternConstants.Email);
            return value.IsMatch(pattern);
        }
        #endregion
        #region "是否是IPV4地址"
        /// <summary>
        /// 是否是IPV4地址
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsIpv4Address(this string value)
        {
            //const string pattern = @"^((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))$";
            string pattern = string.Format("^{0}$", RegexPatternConstants.Ipv4);
            return value.IsMatch(pattern);
        }
        #endregion
        #region "是否是IPV6地址"
        /// <summary>
        /// 是否是IPV6地址
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsIpv6Address(this string value)
        {
            //const string pattern = @"^((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))$";
            string pattern = string.Format("^{0}$", RegexPatternConstants.Ipv6);
            return value.IsMatch(pattern);
        }
        #endregion
        #region "是否是整数"
        /// <summary>
        /// 是否是整数
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsInteger(this string value)
        {
            //const string pattern = @"^\-?[0-9]+$";
            string pattern = string.Format("^{0}$", RegexPatternConstants.Integer);
            return value.IsMatch(pattern);
        }
        #endregion
        #region "是否是Unicode字符串"
        /// <summary>
        /// 是否是Unicode字符串
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsUnicode(this string value)
        {
            //const string pattern = @"^[\u4E00-\u9FA5\uE815-\uFA29]+$";
            string pattern = string.Format("^{0}$", RegexPatternConstants.Unicode);
            return value.IsMatch(pattern);
        }
        #endregion
        #region "是否Url字符串"
        /// <summary>
        /// 是否Url字符串
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsUrl(this string value)
        {
            try
            {
                if (value.IsNullOrEmpty() || value.Contains(' '))
                {
                    return false;
                }
                Uri uri = new(value);
                return true;
            }
            catch (System.Exception)
            {
                return false;
            }
        }
        #endregion
        #region "是否身份证号"
        /// <summary>
        /// 是否身份证号，验证如下3种情况：
        /// 1.身份证号码为15位数字；
        /// 2.身份证号码为18位数字；
        /// 3.身份证号码为17位数字+1个字母
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsIdentityCardId(this string value)
        {
            if (value.Length != 15 && value.Length != 18)
            {
                return false;
            }
            Regex regex;
            string[] array;
            DateTime time;
            if (value.Length == 15)
            {
                regex = new Regex(@"^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})_");
                if (!regex.Match(value).Success)
                {
                    return false;
                }
                array = regex.Split(value);
                return DateTime.TryParse(string.Format("{0}-{1}-{2}", "19" + array[2], array[3], array[4]), out time);
            }
            regex = new Regex(@"^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9Xx])$");
            if (!regex.Match(value).Success)
            {
                return false;
            }
            array = regex.Split(value);
            if (!DateTime.TryParse(string.Format("{0}-{1}-{2}", array[2], array[3], array[4]), out time))
            {
                return false;
            }
            //校验最后一位
            string[] chars = value.ToCharArray().Select(m => m.ToString()).ToArray();
            int[] weights = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
            int sum = 0;
            for (int i = 0; i < 17; i++)
            {
                int num = int.Parse(chars[i]);
                //sum = sum + num * weights[i];
                sum += num * weights[i];
            }
            int mod = sum % 11;
            string vCode = "10X98765432";//检验码字符串
            string last = vCode.ToCharArray().ElementAt(mod).ToString();
            return chars.Last().ToUpper() == last;
        }
        #endregion
        #region "是否手机号码"
        /// <summary>
        /// 是否手机号码
        /// </summary>
        /// <param name="value">值</param>
        /// <param name="isRestrict">是否按严格格式验证</param>
        /// <returns></returns>
        public static bool IsMobileNumber(this string value, bool isRestrict = false)
        {
            string pattern = isRestrict ? @"^[1][3-8]\d{9}$" : @"^[1]\d{10}$";
            return value.IsMatch(pattern);
        }
        #endregion
        #region "是否Cron表达式"
        /// <summary>
        /// 是否Cron表达式
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsCronExpression(this string value)
        {
            //const string pattern = @"^\\s*($|#|\\w+\\s*=|(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?(?:,(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?)*)\\s+(\\?|\\*|(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?(?:,(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?)*)\\s+(\\?|\\*|(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?)*|\\?|\\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\\s+(\\?|\\*|(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?)*|\\?|\\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\\s)+(\\?|\\*|(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?(?:,(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?)*))$";
            string pattern = string.Format("^{0}$", RegexPatternConstants.CronExpression);
            return value.IsMatch(pattern);
        }
        #endregion

        #endregion

        #region "其他操作"
        #region "当字符串是 null 替换为指定值"
        /// <summary>
        /// 当字符串是 null 替换为指定值
        /// </summary>
        /// <param name="value">值</param>
        /// <param name="newValue">替换值</param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public static string ReplaceNull(this string value, string newValue = "")
        {
            return value ?? newValue;
        }
        #endregion
        #region "指示指定的字符串是 null 或者 System.String.Empty 字符串"
        /// <summary>
        /// 指示指定的字符串是 null 或者 System.String.Empty 字符串
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public static bool IsNullOrEmpty(this string value)
        {
            return string.IsNullOrEmpty(value);
        }
        #endregion
        #region "指示指定的字符串是 null、空或者仅由空白字符组成"
        /// <summary>
        /// 指示指定的字符串是 null、空或者仅由空白字符组成
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public static bool IsNullOrWhiteSpace(this string value)
        {
            return string.IsNullOrWhiteSpace(value);
        }
        #endregion
        #region "指示指定的字符串是 null、空或者仅由空白字符组成"
        /// <summary>
        /// 指示指定的字符串是 null、空或者仅由空白字符组成
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public static bool IsMissing(this string value)
        {
            return string.IsNullOrWhiteSpace(value);
        }
        #endregion
        #region "为指定格式的字符串填充相应对象来生成字符串"
        /// <summary>
        /// 为指定格式的字符串填充相应对象来生成字符串
        /// </summary>
        /// <param name="format">字符串格式，占位符以{n}表示</param>
        /// <param name="args">用于填充占位符的参数</param>
        /// <returns>格式化后的字符串</returns>
        [DebuggerStepThrough]
        public static string FormatWith(this string format, params object[] args)
        {
            format.CheckNotNull(nameof(format));
            return string.Format(CultureInfo.CurrentCulture, format, args);
        }
        #endregion
        #region "将字符串反转"
        /// <summary>
        /// 将字符串反转
        /// </summary>
        /// <param name="value">要反转的字符串</param>
        /// <returns>反转后的字符串</returns>
        public static string ReverseString(this string value)
        {
            value.CheckNotNull(nameof(value));
            return new string(value.Reverse().ToArray());
        }
        #endregion
        #region "单词变成单数形式"
        /// <summary>
        /// 单词变成单数形式
        /// </summary>
        /// <param name="word">单词</param>
        /// <returns></returns>
        public static string ToSingular(this string word)
        {
            Regex plural1 = new("(?<keep>[^aeiou])ies$");
            Regex plural2 = new("(?<keep>[aeiou]y)s$");
            Regex plural3 = new("(?<keep>[sxzh])es$");
            Regex plural4 = new("(?<keep>[^sxzhyu])s$");

            if (plural1.IsMatch(word))
            {
                return plural1.Replace(word, "${keep}y");
            }
            if (plural2.IsMatch(word))
            {
                return plural2.Replace(word, "${keep}");
            }
            if (plural3.IsMatch(word))
            {
                return plural3.Replace(word, "${keep}");
            }
            if (plural4.IsMatch(word))
            {
                return plural4.Replace(word, "${keep}");
            }

            return word;
        }
        #endregion
        #region "单词变成复数形式"
        /// <summary>
        /// 单词变成复数形式
        /// </summary>
        /// <param name="word">单词</param>
        /// <returns></returns>
        public static string ToPlural(this string word)
        {
            Regex plural1 = new("(?<keep>[^aeiou])y$");
            Regex plural2 = new("(?<keep>[aeiou]y)$");
            Regex plural3 = new("(?<keep>[sxzh])$");
            Regex plural4 = new("(?<keep>[^sxzhy])$");

            if (plural1.IsMatch(word))
            {
                return plural1.Replace(word, "${keep}ies");
            }
            if (plural2.IsMatch(word))
            {
                return plural2.Replace(word, "${keep}s");
            }
            if (plural3.IsMatch(word))
            {
                return plural3.Replace(word, "${keep}es");
            }
            if (plural4.IsMatch(word))
            {
                return plural4.Replace(word, "${keep}s");
            }

            return word;
        }
        #endregion
        #region "判断指定路径是否图片文件"
        /// <summary>
        /// 判断指定路径是否图片文件
        /// </summary>
        /// <param name="filename">含路径的文件名</param>
        /// <returns></returns>
        public static bool IsImageFile(this string filename)
        {
            if (!File.Exists(filename))
            {
                return false;
            }
            byte[] fileData = File.ReadAllBytes(filename);
            if (fileData.Length == 0)
            {
                return false;
            }
            ushort code = BitConverter.ToUInt16(fileData, 0);
            //switch (code)
            //{
            //    case 0x4D42: //bmp
            //    case 0xD8FF: //jpg
            //    case 0x4947: //gif
            //    case 0x5089: //png
            //        return true;
            //    default:
            //        return false;
            //}
            return code switch
            {
                //bmp     //jpg     //gif     //png
                0x4D42 or 0xD8FF or 0x4947 or 0x5089 => true,
                _ => false,
            };
        }
        #endregion
        #region "以指定字符串作为分隔符将指定字符串分隔成数组"
        /// <summary>
        /// 以指定字符串作为分隔符将指定字符串分隔成数组
        /// </summary>
        /// <param name="value">要分割的字符串</param>
        /// <param name="strSplit">字符串类型的分隔符</param>
        /// <param name="removeEmptyEntries">是否移除数据中元素为空字符串的项</param>
        /// <returns>分割后的数据</returns>
        public static string[] Split(this string value, string strSplit, bool removeEmptyEntries = false)
        {
            if (value.IsMissing())
            {
                return Array.Empty<string>();
            }
            return value.Split(new[] { strSplit }, removeEmptyEntries ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None);
        }
        #endregion
        #region "以指定字符串作为分隔符将指定字符串数组连接成字符串"
        /// <summary>
        /// 以指定字符串作为分隔符将指定字符串数组连接成字符串
        /// </summary>
        /// <param name="value">要转换的字符串数组</param>
        /// <param name="strSplit">字符串类型的分隔符</param>
        /// <param name="removeEmptyEntries">是否移除数据中元素为空字符串的项</param>
        /// <returns>连接后的字符串数据</returns>
        public static string Join(this string[] value, string strSplit, bool removeEmptyEntries = false)
        {
            if (value == null)
            {
                return null;
            }
            if (removeEmptyEntries)
            {
                value = value.Where(s => !string.IsNullOrEmpty(s)).ToArray();
            }
            if (value.Length < 1)
            {
                return "";
            }
            return string.Join(strSplit, value);
        }
        #endregion
        #region "获取字符串的MD5哈希值"
        /// <summary>
        /// 获取字符串的MD5哈希值
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static string ToMD5(this string value)
        {
            return HashHelper.GetMD5(value);
        }
        #endregion
        #region "支持汉字的字符串长度，汉字长度计为2"
        /// <summary>
        /// 支持汉字的字符串长度，汉字长度计为2
        /// </summary>
        /// <param name="value">参数字符串</param>
        /// <returns>当前字符串的长度，汉字长度为2</returns>
        public static int TextLength(this string value)
        {
            ASCIIEncoding ascii = new();
            int tempLen = 0;
            byte[] bytes = ascii.GetBytes(value);
            foreach (byte b in bytes)
            {
                if (b == 63)
                {
                    tempLen += 2;
                }
                else
                {
                    tempLen += 1;
                }
            }
            return tempLen;
        }
        #endregion
        #region "将JSON字符串还原为对象"
        /// <summary>
        /// 将JSON字符串还原为对象
        /// </summary>
        /// <typeparam name="T">要转换的目标类型</typeparam>
        /// <param name="json">JSON字符串</param>
        /// <returns></returns>
        public static T FromJsonString<T>(this string json)
        {
            json.CheckNotNull(nameof(json));
            return JsonConvert.DeserializeObject<T>(json);
        }
        #endregion
        #region "将JSON字符串还原为对象"
        /// <summary>
        /// 将JSON字符串还原为对象
        /// </summary>
        /// <param name="json">JSON字符串 </param>
        /// <param name="type">数据类型</param>
        /// <returns></returns>
        public static object FromJsonString(this string json, Type type)
        {
            return JsonConvert.DeserializeObject(json, type);
        }
        #endregion
        #region "给URL添加查询参数"
        /// <summary>
        /// 给URL添加查询参数
        /// </summary>
        /// <param name="url">URL字符串</param>
        /// <param name="queries">要添加的参数，形如："id=1,cid=2"</param>
        /// <returns></returns>
        public static string AddUrlQuery(this string url, params string[] queries)
        {
            foreach (string query in queries)
            {
                if (!url.Contains("?"))
                {
                    url += "?";
                }
                else if (!url.EndsWith("&"))
                {
                    url += "&";
                }

                url += query;
            }
            return url;
        }
        #endregion
        #region "获取URL中指定参数的值，不存在返回空字符串"
        /// <summary>
        /// 获取URL中指定参数的值，不存在返回空字符串
        /// </summary>
        /// <param name="url">URL</param>
        /// <param name="key">指定参数</param>
        /// <returns></returns>
        public static string GetUrlQuery(this string url, string key)
        {
            Uri uri = new(url);
            string query = uri.Query;
            if (query.IsNullOrEmpty())
            {
                return string.Empty;
            }
            query = query.TrimStart('?');
            var dict = (from m in query.Split("&", true)
                        let strs = m.Split("=")
                        select new KeyValuePair<string, string>(strs[0], strs[1]))
                .ToDictionary(m => m.Key, m => m.Value);
            if (dict.ContainsKey(key))
            {
                return dict[key];
            }
            return string.Empty;
        }
        #endregion
        #region "给URL添加 # 参数"
        /// <summary>
        /// 给URL添加 # 参数
        /// </summary>
        /// <param name="url">URL字符串</param>
        /// <param name="query">要添加的参数</param>
        /// <returns></returns>
        public static string AddHashFragment(this string url, string query)
        {
            if (!url.Contains("#"))
            {
                url += "#";
            }

            return url + query;
        }
        #endregion
        #region "将字符串转换为<see cref="byte"/>[]数组，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 将字符串转换为<see cref="byte"/>[]数组，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="encoding">Encoding编码</param>
        /// <returns></returns>
        public static byte[] ToBytes(this string value, Encoding encoding = null)
        {
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            return encoding.GetBytes(value);
        }
        #endregion
        #region "将字符串转换为Base64字符串，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 将字符串转换为Base64字符串，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="source">正常的字符串</param>
        /// <param name="encoding">编码</param>
        /// <returns>Base64字符串</returns>
        public static string ToBase64String(this string source, Encoding encoding = null)
        {
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            return Convert.ToBase64String(encoding.GetBytes(source));
        }
        #endregion
        #region "将Base64字符串转换为正常字符串，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 将Base64字符串转换为正常字符串，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="base64String">Base64字符串</param>
        /// <param name="encoding">编码</param>
        /// <returns>正常字符串</returns>
        public static string FromBase64String(this string base64String, Encoding encoding = null)
        {
            encoding ??= Encoding.UTF8;
            byte[] bytes = Convert.FromBase64String(base64String);
            return encoding.GetString(bytes);
        }
        #endregion
        #region "将字符串进行UrlDecode解码"
        /// <summary>
        /// 将字符串进行UrlDecode解码
        /// </summary>
        /// <param name="source">待UrlDecode解码的字符串</param>
        /// <returns>UrlDecode解码后的字符串</returns>
        public static string AsUrlDecode(this string source)
        {
            return HttpUtility.UrlDecode(source);
        }
        #endregion
        #region "将字符串进行UrlEncode编码"
        /// <summary>
        /// 将字符串进行UrlEncode编码
        /// </summary>
        /// <param name="source">待UrlEncode编码的字符串</param>
        /// <returns>UrlEncode编码后的字符串</returns>
        public static string AsUrlEncode(this string source)
        {
            return HttpUtility.UrlEncode(source);
        }
        #endregion
        #region "将字符串进行HtmlDecode解码"
        /// <summary>
        /// 将字符串进行HtmlDecode解码
        /// </summary>
        /// <param name="source">待HtmlDecode解码的字符串</param>
        /// <returns>HtmlDecode解码后的字符串</returns>
        public static string AsHtmlDecode(this string source)
        {
            return HttpUtility.HtmlDecode(source);
        }
        #endregion
        #region "将字符串进行HtmlEncode编码"
        /// <summary>
        /// 将字符串进行HtmlEncode编码
        /// </summary>
        /// <param name="source">待HtmlEncode编码的字符串</param>
        /// <returns>HtmlEncode编码后的字符串</returns>
        public static string AsHtmlEncode(this string source)
        {
            return HttpUtility.HtmlEncode(source);
        }
        #endregion
        #region "将字符串转换为十六进制字符串，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 将字符串转换为十六进制字符串，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="source">字符串</param>
        /// <param name="encoding">Encoding编码</param>
        /// <returns></returns>
        public static string ToHexString(this string source, Encoding encoding = null)
        {
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            byte[] bytes = encoding.GetBytes(source);
            return bytes.ToHexString();
        }
        #endregion
        #region "将十六进制字符串转换为常规字符串，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 将十六进制字符串转换为常规字符串，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="hexString">十六进制字符串</param>
        /// <param name="encoding">Encoding编码</param>
        /// <returns></returns>
        public static string FromHexString(this string hexString, Encoding encoding = null)
        {
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            byte[] bytes = hexString.ToHexBytes();
            return encoding.GetString(bytes);
        }
        #endregion
        #region "将十六进制字符串转换为byte[]"
        /// <summary>
        /// 将十六进制字符串转换为byte[]
        /// </summary>
        /// <param name="hexString">十六进制字符串</param>
        /// <returns>byte[]数组</returns>
        public static byte[] ToHexBytes(this string hexString)
        {
            hexString ??= "";
            hexString = hexString.Replace(" ", "");
            byte[] bytes = new byte[hexString.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return bytes;
        }
        #endregion
        #region "将字符串进行Unicode编码，变成形如“\u7f16\u7801”的形式"
        /// <summary>
        /// 将字符串进行Unicode编码，变成形如“\u7f16\u7801”的形式
        /// </summary>
        /// <param name="source">要进行编号的字符串</param>
        /// <returns></returns>
        public static string ToUnicodeString(this string source)
        {
            Regex regex = new(@"[^\u0000-\u00ff]");
            return regex.Replace(source, m => string.Format(@"\u{0:x4}", (short)m.Value[0]));
        }
        #endregion
        #region "将形如“\u7f16\u7801”的Unicode字符串解码"
        [GeneratedRegex("\\\\u([0-9a-fA-F]{4})", RegexOptions.Compiled)]
        private static partial Regex UnicodeRegex();
        /// <summary>
        /// 将形如“\u7f16\u7801”的Unicode字符串解码
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns></returns>
        public static string FromUnicodeString(this string source)
        {
            Regex regex = UnicodeRegex();
            return regex.Replace(source,
                m =>
                {
                    if (short.TryParse(m.Groups[1].Value, NumberStyles.HexNumber, CultureInfo.InstalledUICulture, out short s))
                    {
                        return "" + (char)s;
                    }
                    return m.Value;
                });
        }
        #endregion
        #region "将驼峰字符串按单词拆分并转换成小写，再以特定字符串分隔"
        /// <summary>
        /// 将驼峰字符串按单词拆分并转换成小写，再以特定字符串分隔
        /// </summary>
        /// <param name="str">待转换的字符串</param>
        /// <param name="splitStr">分隔符字符</param>
        /// <returns></returns>
        public static string UpperToLowerAndSplit(this string str, string splitStr = "-")
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }
            List<string> words = new();
            while (str.Length > 0)
            {
                char c = str.FirstOrDefault(char.IsUpper);
                if (c == default(char))
                {
                    words.Add(str);
                    break;
                }
                int upperIndex = str.IndexOf(c);
                if (upperIndex < 0) //admin
                {
                    return str;
                }
                if (upperIndex > 0) //adminAdmin
                {
                    string first = str.Substring(0, upperIndex);
                    words.Add(first);
                    str = str.Substring(upperIndex, str.Length - upperIndex);
                    continue;
                }
                str = char.ToLower(str[0]) + str.Substring(1, str.Length - 1);
            }
            return words.ExpandAndToString(splitStr);
        }
        #endregion
        #region "将驼峰字符串的第一个字符小写"
        /// <summary>
        /// 将驼峰字符串的第一个字符小写
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static string ToLowerCase(this string str)
        {
            if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0]))
            {
                return str;
            }
            if (str.Length == 1)
            {
                return char.ToLower(str[0]).ToString();
            }
            return char.ToLower(str[0]) + str.Substring(1, str.Length - 1);
        }
        #endregion
        #region "将小驼峰字符串的第一个字符大写"
        /// <summary>
        /// 将小驼峰字符串的第一个字符大写
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static string ToUpperCase(this string str)
        {
            if (string.IsNullOrEmpty(str) || !char.IsLower(str[0]))
            {
                return str;
            }
            if (str.Length == 1)
            {
                return char.ToUpper(str[0]).ToString();
            }
            return char.ToUpper(str[0]) + str.Substring(1, str.Length - 1);
        }
        #endregion
        #region "计算当前字符串与指定字符串的编辑距离(相似度)"
        /// <summary>
        /// 计算当前字符串与指定字符串的编辑距离(相似度)
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="similarity">输出相似度</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns>编辑距离</returns>
        public static int LevenshteinDistance(this string source, string target, out double similarity, bool ignoreCase = false)
        {
            if (string.IsNullOrEmpty(source))
            {
                if (string.IsNullOrEmpty(target))
                {
                    similarity = 1;
                    return 0;
                }
                similarity = 0;
                return target.Length;
            }
            if (string.IsNullOrEmpty(target))
            {
                similarity = 0;
                return source.Length;
            }

            string from, to;
            if (!ignoreCase)
            {
                from = source;
                to = target;
            }
            else
            {
                from = source.ToLower();
                to = target.ToLower();
            }

            int m = from.Length, n = to.Length;
            int[,] mn = new int[m + 1, n + 1];
            for (int i = 0; i <= m; i++)
            {
                mn[i, 0] = i;
            }
            for (int j = 1; j <= n; j++)
            {
                mn[0, j] = j;
            }
            for (int i = 1; i <= m; i++)
            {
                char c = from[i - 1];
                for (int j = 1; j <= n; j++)
                {
                    if (c == to[j - 1])
                    {
                        mn[i, j] = mn[i - 1, j - 1];
                    }
                    else
                    {
                        mn[i, j] = Math.Min(mn[i - 1, j - 1], Math.Min(mn[i - 1, j], mn[i, j - 1])) + 1;
                    }
                }
            }

            int maxLength = Math.Max(m, n);
            similarity = (double)(maxLength - mn[m, n]) / maxLength;
            return mn[m, n];
        }
        #endregion
        #region "计算两个字符串的相似度，应用公式：相似度=kq*q/(kq*q+kr*r+ks*s)(kq>0,kr>=0,ka>=0)"
        /// <summary>
        /// 计算两个字符串的相似度，应用公式：相似度=kq*q/(kq*q+kr*r+ks*s)(kq>0,kr>=0,ka>=0)
        /// 其中，q是字符串1和字符串2中都存在的单词的总数，s是字符串1中存在，字符串2中不存在的单词总数，r是字符串2中存在，字符串1中不存在的单词总数. kq,kr和ka分别是q,r,s的权重，根据实际的计算情况，我们设kq=2，kr=ks=1.
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns>字符串相似度</returns>
        public static double GetSimilarityWith(this string source, string target, bool ignoreCase = false)
        {
            if (ignoreCase)
            {
                source = source.ToLower();
                target = target.ToLower();
            }
            if (string.IsNullOrEmpty(source) && string.IsNullOrEmpty(target)) { return 1; }
            if (source == target) { return 1; }
            if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target)) { return 0; }

            const double kq = 2, kr = 1, ks = 1;
            char[] sourceChars = source.ToCharArray(), targetChars = target.ToCharArray();

            //获取交集数量
            int q = sourceChars.Intersect(targetChars).Count(), s = sourceChars.Length - q, r = targetChars.Length - q;
            return kq * q / (kq * q + kr * r + ks * s);
        }
        #endregion
        #region "将字符串转换为字典数据"
        /// <summary>
        /// 将字符串转换为字典数据，形如“Name=MicroCloud;Key=C2y6yDjf5/Jw==”
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="split">分隔符</param>
        /// <param name="connector">用分割符处理成数组后字符串连接符，字符串左边一个匹配符</param>
        /// <returns></returns>
        public static Dictionary<string, string> ToDictionary(this string value, string split = ";", string connector = "=")
        {
            Dictionary<string, string> dictionaryData = new();
            if (value.IsMissing()) { return dictionaryData; }

            var valueArry = value.Split(split, true);
            foreach (var item in valueArry)
            {
                if (!item.Contains(connector))
                {
                    dictionaryData.Add(item, item);
                    continue;
                }
                var stringKey = item.Split(connector, true)[0];
                //var stringValue = item.Substring(item.IndexOf(connector), item.Length - item.IndexOf(connector));
                var stringValue = item[item.IndexOf(connector)..];

                dictionaryData.Add(stringKey, stringValue);
            }

            return dictionaryData;
        }
        #endregion

        #region "确定两个字符串是否匹配(忽略大小写)"
        /// <summary>
        /// 确定两个字符串是否匹配(忽略大小写)
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <returns></returns>
        public static bool EqualsIgnoreCase(this string source, string target)
        {
            return source.Equals(target, true);
        }
        #endregion
        #region "确定指定的字符串是否是当前实例的前缀(忽略大小写)"
        /// <summary>
        /// 确定指定的字符串是否是当前实例的前缀(忽略大小写)
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <returns></returns>
        public static bool StartsWithIgnoreCase(this string source, string target)
        {
            return source.StartsWith(target, true);
        }
        #endregion
        #region "确定指定的字符串是否是当前实例的后缀(忽略大小写)"
        /// <summary>
        /// 确定指定的字符串是否是当前实例的后缀(忽略大小写)
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <returns></returns>
        public static bool EndsWithIgnoreCase(this string source, string target)
        {
            return source.EndsWith(target, true);
        }
        #endregion
        #region "确定指定的字符串是否包含在当前实例中(忽略大小写)"
        /// <summary>
        /// 确定指定的字符串是否包含在当前实例中(忽略大小写)
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <returns></returns>
        public static bool ContainsIgnoreCase(this string source, string target)
        {
            return source.Contains(target, true);
        }
        #endregion
        #region "Base64字符串标头正则表达式(只读字段)"
        /// <summary>
        /// 获取Base64字符串标头正则表达式
        /// </summary>
        /// <returns></returns>
        [GeneratedRegex("^[\\w/\\:.-]+;base64,")]
        private static partial Regex GetBase64StringRegex();
        /// <summary>
        /// Base64字符串标头正则表达式
        /// </summary>
        private static readonly Regex Base64StringHeaderRegex = GetBase64StringRegex();
        #endregion
        #region "判断字符串是否为Base64字符串"
        /// <summary>
        /// 判断字符串是否为Base64字符串
        /// </summary>
        /// <param name="base64String">要判断的字符串</param>
        /// <returns></returns>
        public static bool IsBase64String(this string base64String)
        {
            var flag = Base64StringHeaderRegex.IsMatch(base64String);
            return flag;
        }
        #endregion
        #region "获取Base64字符串标头"
        /// <summary>
        /// 获取Base64字符串标头
        /// </summary>
        /// <param name="base64String">要处理的字符串</param>
        /// <returns></returns>
        public static string GetBase64StringHeader(this string base64String)
        {
            var base64StringHeader = Base64StringHeaderRegex.Match(base64String).Value;
            return base64StringHeader;
        }
        #endregion
        #region "移除Base64字符串标头"
        /// <summary>
        /// 移除Base64字符串标头
        /// </summary>
        /// <param name="base64String">要处理的字符串</param>
        /// <returns></returns>
        public static string RemoveBase64StringHeader(this string base64String)
        {
            var base64StringWithoutHeader = Base64StringHeaderRegex.Replace(base64String, string.Empty);
            return base64StringWithoutHeader;
        }
        #endregion
        #region "将Base64字符串转换为 <see cref="byte"/>[]"
        /// <summary>
        /// 将Base64字符串转换为 <see cref="byte"/>[]
        /// </summary>
        /// <param name="base64String">要处理的字符串</param>
        /// <returns></returns>
        public static byte[] ToBytesFromBase64String(this string base64String)
        {
            return Convert.FromBase64String(base64String.RemoveBase64StringHeader());
        }
        #endregion
        #region "将Base64字符串转换为 <see cref="Stream"/>"
        /// <summary>
        /// 将Base64字符串转换为 <see cref="Stream"/>
        /// </summary>
        /// <param name="base64String">要处理的字符串</param>
        /// <returns></returns>
        public static Stream ToStreamFromBase64String(this string base64String)
        {
            return base64String.ToBytesFromBase64String().ToStream();
        }
        #endregion
        #region "将Base64字符串转换为 <see cref="MemoryStream"/>"
        /// <summary>
        /// 将Base64字符串转换为 <see cref="MemoryStream"/>
        /// </summary>
        /// <param name="base64String">要处理的字符串</param>
        /// <returns></returns>
        public static MemoryStream ToMemoryStreamFromBase64String(this string base64String)
        {
            return base64String.ToBytesFromBase64String().ToMemoryStream();
        }
        #endregion

        #region "获取文件名称字符串中的扩展名"
        /// <summary>
        /// 获取文件名称字符串中的扩展名
        /// </summary>
        /// <param name="fileName">文件名称</param>
        /// <returns></returns>
        public static string GetFileExtname(this string fileName)
        {
            var fileExtension = Path.GetExtension(fileName);
            return fileExtension;
        }
        #endregion
        #region "替换文件名称字符串中的扩展名"
        /// <summary>
        /// 替换文件名称字符串中的扩展名
        /// </summary>
        /// <param name="fileName">文件名称</param>
        /// <param name="newValue">替换的字符串</param>
        /// <returns></returns>
        public static string ReplaceFileExtname(this string fileName, string newValue = "")
        {
            var fileExtname = fileName.GetFileExtname();
            var newfileName = fileName.Replace(fileExtname, newValue);
            return newfileName;
        }
        #endregion

        #endregion

        #region "私有方法"
        #region "确定两个字符串是否匹配"
        /// <summary>
        /// 确定两个字符串是否匹配
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns></returns>
        private static bool Equals(this string source, string target, bool ignoreCase)
        {
            string from, to;
            if (!ignoreCase)
            {
                from = source;
                to = target;
            }
            else
            {
                from = source?.ToLower();
                to = target?.ToLower();
            }

            return string.Equals(from, to);
        }
        #endregion
        #region "确定指定的字符串是否是当前实例的前缀"
        /// <summary>
        /// 确定指定的字符串是否是当前实例的前缀
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns></returns>
        private static bool StartsWith(this string source, string target, bool ignoreCase)
        {
            string from, to;
            if (!ignoreCase)
            {
                from = source;
                to = target;
            }
            else
            {
                from = source?.ToLower();
                to = target?.ToLower();
            }

            return from?.StartsWith(to) == true;
        }
        #endregion
        #region "确定指定的字符串是否是当前实例的后缀"
        /// <summary>
        /// 确定指定的字符串是否是当前实例的后缀
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns></returns>
        private static bool EndsWith(this string source, string target, bool ignoreCase)
        {
            string from, to;
            if (!ignoreCase)
            {
                from = source;
                to = target;
            }
            else
            {
                from = source?.ToLower();
                to = target?.ToLower();
            }

            return from?.EndsWith(to) == true;
        }
        #endregion
        #region "确定指定的字符串是否包含在当前实例中"
        /// <summary>
        /// 确定指定的字符串是否包含在当前实例中
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns></returns>
        private static bool Contains(this string source, string target, bool ignoreCase)
        {
            string from, to;
            if (!ignoreCase)
            {
                from = source;
                to = target;
            }
            else
            {
                from = source?.ToLower();
                to = target?.ToLower();
            }

            return from?.Contains(to) == true;
        }
        #endregion
        #region "类似 SQL <c>LIKE</c> 的操作实现"
        /// <summary>
        /// 类似 SQL <c>LIKE</c> 的操作实现
        /// </summary>
        /// <param name="matchExpression">要匹配的字符串</param>
        /// <param name="pattern">可能涉及通配符%、_、[、]、^的字符串</param>
        /// <param name="escapeCharacter">如果%、_、[、]、^未用作通配符，则在它们前面使用的转义符（作为单个字符串）。</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns></returns>
        private static bool Like(this string matchExpression, string pattern, string escapeCharacter, bool ignoreCase)
        {
            if (matchExpression == null)
            {
                return false;
            }

            string matchString, patternString;
            if (!ignoreCase)
            {
                matchString = matchExpression;
                patternString = pattern;
            }
            else
            {
                matchString = matchExpression?.ToLower();
                patternString = pattern?.ToLower();
            }

            if (escapeCharacter.IsMissing())
            {
                string convertedPattern = EscapeRegexMetaChars(patternString).Replace("_", ".").Replace("%", ".*");
                convertedPattern = string.Format("^{0}$", convertedPattern);

                return Regex.IsMatch(matchString, convertedPattern, RegexOptions.Singleline);
            }
            else
            {
                string convertedPattern = EscapeRegexMetaChars(patternString);
                convertedPattern = ReplaceWildcards(convertedPattern, "_", ".", escapeCharacter);
                convertedPattern = ReplaceWildcards(convertedPattern, "%", ".*", escapeCharacter);
                convertedPattern = string.Format("^{0}$", convertedPattern);

                return Regex.IsMatch(matchString, convertedPattern, RegexOptions.Singleline);
            }
        }
        #endregion
        #region "返回当前实例中指定字符出现的索引"
        /// <summary>
        /// 返回当前实例中指定字符出现的索引
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns></returns>
        private static int IndexOf(this string source, string target, bool ignoreCase)
        {
            if (source.IsMissing())
            {
                return -1;
            }
            string from, to;
            if (!ignoreCase)
            {
                from = source;
                to = target;
            }
            else
            {
                from = source?.ToLower();
                to = target?.ToLower();
            }

            return from.IndexOf(to);
        }
        #endregion
        #region "返回当前实例中指定字符出现的索引"
        /// <summary>
        /// 返回当前实例中指定字符出现的索引
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <param name="startIndex">起始索引位置</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns></returns>
        private static int IndexOf(this string source, string target, int startIndex, bool ignoreCase)
        {
            if (source.IsMissing())
            {
                return -1;
            }
            string from, to;
            if (!ignoreCase)
            {
                from = source;
                to = target;
            }
            else
            {
                from = source?.ToLower();
                to = target?.ToLower();
            }

            return from.IndexOf(to, startIndex);
        }
        #endregion

        #region "替换通配符"
        /// <summary>
        /// Replace wildcards
        /// </summary>
        /// <param name="replacement">The replacement string</param>
        /// <param name="wildcard">The wildcard</param>
        /// <param name="replaceTo">The replace wild char to</param>
        /// <param name="escapeChar">The escape char</param>
        /// <returns>The converted search value</returns>
        private static string ReplaceWildcards(string replacement, string wildcard, string replaceTo, string escapeChar)
        {
            string regexExpression = string.Format("(^|[^{0}])({1}+)", escapeChar, wildcard);
            return Regex.Replace(replacement, regexExpression, match => string.Format("{0}{1}", match.Groups[1].Value, match.Groups[2].Value.Replace(wildcard.ToString(), replaceTo)))
                .Replace(string.Format("{0}{1}", escapeChar, wildcard), wildcard.ToString());
        }
        #endregion
        #region "转义正则表达式元字符"
        /// <summary>
        /// Escape regex meta chars
        /// </summary>
        /// <param name="replacement">The replacement string</param>
        /// <returns>The converted search value</returns>
        private static string EscapeRegexMetaChars(string replacement)
        {
            string resultString = replacement;
            foreach (string metaChar in REGEX_META_CHARS)
            {
                resultString = resultString.Replace(metaChar, string.Format(@"\{0}", metaChar));
            }
            return resultString;
        }
        #endregion

        #endregion
    }
}
